# coding= utf-8

import requests
import json
import sys
import codecs
import warnings
import pymongo
import time
from bson.objectid import ObjectId

sys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach())
warnings.filterwarnings("ignore")


class Keepa:
    def __init__(self):
        self.api_prefix = 'https://api.keepa.com/product'
        self.api_current = ''
        self.api_key = 'cqqkcu49mds3vp4u4v8om3qtmmfl4l63038r1httn5tun9tu155u39k4kpkbsj2k'  # 付费token
        self.asset_url = 'https://m.media-amazon.com/images/I/'
        self.token_url = 'https://api.keepa.com/token'
        self.client_url = ''
        self.client_task_id = ''
        self.asin_list = []
        self.asin_total = []
        self.domain = ''
        self.recent_update = 0
        self.task_counts = 0
        self.time_gte = 0
        # self.task_id = '66a7023fe520cb891707f923'
        self.task_id = sys.argv[1]

        # 连接MongoDB
        self.myclient = pymongo.MongoClient("mongodb://localhost:27017/")
        mydb = self.myclient["amazon_local"]
        self.my_asin = mydb["amazon_asin"]
        self.my_product = mydb["amazon_product"]
        self.my_task = mydb["client_task"]

    def get_asin(self, domain, item):
        asin = ','.join(item)
        url = self.api_prefix
        params = {
            'key': self.api_current,
            'domain': int(domain),
            'asin': asin,
            'rating': 1,
            'stats': 180,
            'update': 6,
            'history': 0
        }
        response = requests.get(url=url, params=params)

        # 判断状态码
        status_code = response.status_code
        if not int(status_code) == 200:
            print('状态码：' + str(status_code) + '请求失败，等待下次重试！')
            # self.myclient.close()
            # exit()
        else:
            res = json.loads(response.text)

            # 请求成功添加至数据库
            my_list = []

            # 判断请求是否成功
            if "error" in res:
                print(res['error']['message'])

            if "products" in res:
                for i in res['products']:
                    category_tree_list = []

                    if 'imagesCSV' in i and not i['imagesCSV'] == None:
                        image = i['imagesCSV'].split(',')[0]
                    else:
                        image = ''

                    # 获取分类以及分类树
                    if 'categoryTree' in i:
                        category_tree = i['categoryTree']
                    else:
                        category_tree = ''
                    if category_tree:
                        for tree in category_tree:
                            category_tree_list.append(tree['name'])

                    # 获取售价
                    price_origin = int(i['stats']['current'][1])
                    price_origin_30 = int(i['stats']['avg30'][1])
                    price_origin_90 = int(i['stats']['avg90'][1])
                    price_origin_180 = int(i['stats']['avg180'][1])
                    if price_origin:
                        price_current = round(price_origin / 100.0, 2)
                    else:
                        price_current = 0
                    if price_origin_30:
                        price_30 = round(price_origin_30 / 100.0, 2)
                    else:
                        price_30 = 0
                    if price_origin_90:
                        price_90 = round(price_origin_90 / 100.0, 2)
                    else:
                        price_90 = 0
                    if price_origin_180:
                        price_180 = round(price_origin_180 / 100.0, 2)
                    else:
                        price_180 = 0

                    # 星级
                    reviews_rating = round(float(i['stats']['current'][16]) / 100.0, 2)

                    value = dict([
                        ['task_id', self.task_id],
                        ['client_task_id', self.client_task_id],
                        ['domainId', int(domain)],
                        ['asin', i.get('asin', '')],
                        ['image', image],
                        ['imagesCSV', i.get('imagesCSV','')],
                        ['title', i.get('title', '')],
                        ['manufacturer', i.get('manufacturer', '')],
                        ['brand', i.get('brand', '')],
                        ['productGroup', i.get('productGroup', '')],
                        ['partNumber', i.get('partNumber', '')],
                        ['color', i.get('color', '')],
                        ['size', i.get('size', '')],
                        ['categoryTree', i.get('categoryTree', '')],
                        ['categoryTreeStr', ' > '.join(category_tree_list)],
                        ['description', i.get('description', '')],
                        ['salesRankReference', i.get('salesRankReference', '')],
                        ['sales_rank_current', int(i['stats']['current'][3])],
                        ['sales_rank_30_days_avg', int(i['stats']['avg30'][3])],
                        ['sales_rank_90_days_avg', int(i['stats']['avg90'][3])],
                        ['sales_rank_180_days_avg', int(i['stats']['avg180'][3])],
                        ['buy_box_current', price_current],
                        ['buy_box_30_days_avg', price_30],
                        ['buy_box_90_days_avg', price_90],
                        ['buy_box_180_days_avg', price_180],
                        ['monthlySold', i.get('monthlySold', '')],
                        ['reviews_rating', reviews_rating],
                        ['reviews_review_count', int(i['stats']['current'][17])],
                        ['packageHeight', i.get('packageHeight', '')],
                        ['packageLength', i.get('packageLength', '')],
                        ['packageWeight', i.get('packageWeight', '')],
                        ['itemHeight', i.get('itemHeight', '')],
                        ['itemLength', i.get('itemLength', '')],
                        ['itemWidth', i.get('itemWidth', '')],
                        ['itemWeight', i.get('itemWeight', '')],
                        ['lastUpdate', translate_time(i.get('lastUpdate', ''))],
                        ['lastPriceChange', translate_time(i.get('lastPriceChange', ''))],
                        ['created_at', time.time()],
                    ])
                    my_list.append(value)

                # print(my_list)
                # exit()
                if len(my_list) > 0:
                    result = self.my_product.insert_many(my_list)
                    # 检查插入操作是否成功
                    if result.acknowledged:
                        print('获取产品成功，共计' + str(len(my_list)) + '条！')
                    else:
                        print('插入失败，等待下次重新获取！')
                else:
                    print('本次请求无给定asin列表数据！')

                # 标记已获取产品信息的asin
                if self.my_asin.update_many({'asin': {'$in': item}, "domainId": self.domain}, {'$set': {'has_get_product': 1, 'get_product_time': time.time()}}):
                    print('标记已获取信息asin，共计' + str(len(item)) + '条！')
                else:
                    print('标记失败，等待下次标记！')

                # 将产品数据返回客户端
                self.send_to_client(my_list)

            else:
                print('返回结果无产品！')
            # self.myclient.close()
            # exit()

    def send_to_client(self, data):

        self.my_task.update_one({"_id": ObjectId(self.task_id)}, {"$set": {"status": 'completed'}})

        headers = {'Content-Type': 'application/json'}

        # 携带的数据，这里以JSON为例
        data = {
            'client_task_id': self.client_task_id,
            'product_info': remove_id_fields(data)
        }

        # 发送POST请求
        response = requests.post(self.client_url + '/api/get_task_data', json=data, headers=headers)

        # 打印响应状态码
        print(response.status_code)

        # 如果服务器返回的是JSON格式的数据，可以直接转换为Python字典
        print(response.json())

    def pre_asin(self):
        # 判断令牌剩余数量
        params = {
            'key': self.api_key
        }
        response = requests.get(url=self.token_url, params=params)
        res = json.loads(response.text)
        token_left = int(res['tokensLeft'])

        # 令牌不足退出
        if token_left < 300:
            print('Token不足， 剩余 ' + str(token_left))
            # self.myclient.close()
            # exit()
        else:
            print('Token剩余 ' + str(token_left))
            self.api_current = self.api_key

            # 等待获取的asin列表集合
            asin_wait = []
            for i in self.asin_list:
                if 'has_get_product' not in i:
                    if i['asin'] not in asin_wait:
                        asin_wait.append(i['asin'])
                else:
                    if self.recent_update and 'get_product_time' in i and i['get_product_time'] < self.time_gte:
                        if i['asin'] not in asin_wait:
                            asin_wait.append(i['asin'])

            # 获取keepa产品信息
            if len(asin_wait) > 0:
                print('需要跑')
                new_list = split_list_by_n(asin_wait, 100)
                for item in new_list:
                    self.get_asin(self.domain, item)
            else:
                products = self.my_product.find({'domainId': self.domain, 'asin': {'$in': self.asin_total}}).limit(int(self.task_counts))
                self.send_to_client(list(products))

    def run_test(self):
        # 更新状态为处理中
        task = self.my_task.find_one({"_id": ObjectId(self.task_id)})
        self.my_task.update_one({"_id": ObjectId(self.task_id)}, {"$set": {"status": 'pending'}})
        self.domain = task['domain_id']
        self.task_counts = task['counts']
        self.client_url = task['request_url'] + '/'
        self.recent_update = task['recent_update']
        self.client_task_id = task['client_task_id']
        self.time_gte = int(task['client_create_time']) - 3600*24*3
        print(task)

        # 获取所有该计划的asin
        asin_match = {
            'domainId': task['domain_id'],
            'catId': task['cat_id'],
            'sort_key': {'$gte': task['sales_rank_low'], '$lte': task['sales_rank_high']},
        }
        all_asin = self.my_asin.find(asin_match).limit(int(task['counts']))
        self.asin_list = list(all_asin)
        for asin in self.asin_list:
            self.asin_total.append(asin['asin'])

        print(len(self.asin_list))
        print('获取所有该计划的asin')
        self.pre_asin()


def remove_id_fields(data_list):
    """
    从列表中的每个字典中删除'_id'字段。

    参数:
    - data_list: 包含字典的列表。

    返回:
    - 新的列表，其中每个字典都不包含'_id'字段。
    """
    return [{k: v for k, v in d.items() if k != '_id'} for d in data_list]


def split_list_by_n(lst, n):
    """
    将列表lst分割成每n个元素为一个子列表
    """
    # 使用列表推导式和range()来分割列表
    return [lst[i:i + n] for i in range(0, len(lst), n)]


def translate_time(keepa_time):
    return (keepa_time + 21564000) * 60


keepa = Keepa()
keepa.run_test()


